#include "broker.h"
#include "auth.hpp"

#define TIMER_ID		10000
#define TIMER_ID_CON	TIMER_ID + 1
#define TIMER_ID_HEART	TIMER_ID + 2

CBrokerImpl::CBrokerImpl(void)
{
	
}
CBrokerImpl::~CBrokerImpl(void)
{
	logi("CBrokerImpl::~CBrokerImpl");
}
std_method_impl CBrokerImpl::Listen(LPCSTR addr, int len, int maxconn)
{
	m_MaxConn = maxconn;

	HRESULT hr = S_OK;

	hr = Init();
	rc_assert(hr == S_OK, E_FAIL)

	hr = ListenChannel(addr, len);
	rc_assert(hr == S_OK, E_FAIL)

	return hr;
}
std_method_impl CBrokerImpl::Dispatch(unsigned int sec)
{
	HRESULT hr = S_OK;

	hr = AcceptCChannel();
	rc_assert(hr == S_OK, E_FAIL)

	loge("CBrokerImpl::Dispatch\n");

	m_sem.WaitTime(sec);

	return hr;
}

std_method_impl CBrokerImpl::Close()
{
	HRESULT hr = S_OK;

	hr = UnInit();
	rc_assert(hr == S_OK, E_FAIL)

	hr = this->SChannel::CloseChannel();
	rc_assert(hr == S_OK, E_FAIL)

	return hr;
}
std_method_impl CBrokerImpl::IsListen()
{
	return IsListenChannel();
}
std_method_impl CBrokerImpl::Accept(IBase* pBase, _sock_t s, event_id error_code)
{
	HRESULT hr = S_OK;
	rc_assert(pBase != NULL, E_FAIL)

	if (S_SUCCESS == error_code) {

		hr = OnAccepted(pBase, s);
		if (S_FAILED(hr))
			goto end;

		hr = AcceptCChannel();
		if (S_FAILED(hr))
			goto end;
	} 
end:
	pBase->Release();
	return hr;
}

std_method_impl CBrokerImpl::OnComplete(IBase *pOperation, event_id event, ULONG error_code)
{

	if (error_code == S_SUCCESS) {

		switch (event)
		{
		case BUS_OP_RECV_SEQ:
			OnRecvSeqed(pOperation);
			break;
		case BUS_OP_SEND_SEQ_ACK:
			OnSendSeqAcked(pOperation);
			break;
		case BUS_OP_RECV_ACK:
			OnRecvAcked(pOperation);
			break;
		case BUS_OP_SEND:
			break;
		case BUS_OP_RECV:
			break;
		default:
			loge("CBrokerImpl::OnComplete");
			break;
		}
	}
	else {
		loge("CBrokerImpl::OnComplete::error %u", error_code);
	}
	return S_OK;
}
std_method_impl CBrokerImpl::OnTimer(UINT uId, UINT err)
{
	//logi("id==>%u", uId);
	return S_OK;
}
std_method_impl CBrokerImpl::OnAccepted(IBase* pBase, _sock_t s)
{
	HRESULT hr = S_OK;

	TcpSocketPtr pSocket;

	hr = pBase->QueryInterface(IID_ITcpSocket, (void**)&pSocket);
	rc_assert(hr == S_OK, E_FAIL)

	hr = pSocket->AttachSock(s);
	rc_assert(hr == S_OK, E_FAIL)

	OperationPtr WriteOperation;
	hr = m_pIAsynFrame->CreateIo(io_operation, (IBase**)&WriteOperation);
	rc_assert(hr == S_OK, E_FAIL)

	BasePtr pEventBase;
	hr = this->QueryInterface(IID_IBase, (void**)&pEventBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = WriteOperation->BindEvent(pEventBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = WriteOperation->BindIBase(pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = WriteOperation->SetExpect(BUS_PROTOCOL_HEAD_LEN);
	rc_assert(hr == S_OK, E_FAIL)

	hr = pSocket->ReadIo(WriteOperation, BUS_OP_RECV_SEQ);
	rc_assert(hr == S_OK, E_FAIL)

	WriteOperation->AddRef();

	return S_OK;
}
std_method_impl CBrokerImpl::OnRecvSeqed(IBase *pIBase)
{
	HRESULT hr = S_OK;

	TcpSocketPtr	pIScoket;
	OperationPtr	pIOperation;
	hr = GetObject(pIBase, pIScoket, pIOperation);
	rc_assert(hr == S_OK, E_FAIL)

	BUFFER_SIZE		TransferedBytes = 0;
	BUFFER_PTR		ptr = NULL;

	hr = pIOperation->GetTransfered(&TransferedBytes);
	rc_assert(TransferedBytes != 0, E_FAIL)
	
	hr = pIOperation->GetPtr(&ptr);
	rc_assert(hr == S_OK, E_FAIL)

	unsigned int s = 0;
	unsigned int a = 0;

	BusProtocol_Get_Seq_Ack(ptr, &s, &a);
	logi("s_recv==>seq:%u,ack:%u", s, a);

	BusProtocol_2nd(ptr,  BUS_ACK_VALUE, s);

	Send(pIScoket, pIOperation, BUS_PROTOCOL_HEAD_LEN, BUS_OP_SEND_SEQ_ACK);

	return hr;
}
std_method_impl CBrokerImpl::OnSendSeqAcked(IBase *pIBase)
{
	HRESULT hr = S_OK;

	TcpSocketPtr	pIScoket;
	OperationPtr	pIOperation;

	hr = GetObject(pIBase, pIScoket, pIOperation);
	rc_assert(hr == S_OK, E_FAIL)

	hr = Recv(pIScoket, pIOperation, BUS_PROTOCOL_HEAD_LEN, BUS_OP_RECV_ACK);
	rc_assert(hr == S_OK, E_FAIL)

	return hr;
}
std_method_impl CBrokerImpl::OnRecvAcked(IBase *pIBase)
{
	HRESULT hr = S_OK;

	TcpSocketPtr	pIScoket;
	OperationPtr	pIOperation;
	BUFFER_SIZE		TransferedBytes = 0;
	BUFFER_PTR		ptr = NULL;
	unsigned int	s = 0;
	unsigned int	a = 0;

	hr = GetObject(pIBase, pIScoket, pIOperation);
	rc_assert(hr == S_OK, E_FAIL)

	hr = pIOperation->GetTransfered(&TransferedBytes);
	rc_assert(TransferedBytes != 0, E_FAIL)

	hr = pIOperation->GetPtr(&ptr);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_Get_Seq_Ack(ptr, &s, &a);
	rc_assert(hr == S_OK, E_FAIL)

	logi("s_recv==>seq:%u,ack:%u", s, a);
	logi("s_recv==>accept_bus_client");

	return hr;
}

std_method_impl CBrokerImpl::OnSended(IBase *pIBase)
{
	HRESULT hr = S_OK;

	TcpSocketPtr	pIScoket;
	OperationPtr	pIOperation;

	hr = GetObject(pIBase, pIScoket, pIOperation);
	rc_assert(hr == S_OK, E_FAIL)

	return hr;
}
std_method_impl CBrokerImpl::OnRecved(IBase *pIBase)
{
	HRESULT hr = S_OK;

	TcpSocketPtr	pIScoket;
	OperationPtr	pIOperation;

	hr = GetObject(pIBase, pIScoket, pIOperation);
	rc_assert(hr == S_OK, E_FAIL)

	return hr;
}

std_method_impl CBrokerImpl::Init()
{
	SYNC_OBJ(&m_lock);
		
	HRESULT hr = S_OK;

	hr = this->UnBindEvent();
	rc_assert(hr == S_OK, E_FAIL)

	BasePtr pBase;

	hr = this->QueryInterface(IID_IBase, (void**)&pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = this->BindEvent(pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_pIAsynFrame->CreateIo(io_timer, (IBase**)&m_ConnectTimer);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_ConnectTimer->SetId(TIMER_ID_CON);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_ConnectTimer->Bind(pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_ConnectTimer->SetSec(5);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_ConnectTimer->Start();
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_pIAsynFrame->CreateIo(io_timer, (IBase**)&m_HeartTimer);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_HeartTimer->SetId(TIMER_ID_HEART);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_HeartTimer->Bind(pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_HeartTimer->SetSec(5);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_HeartTimer->Start();
	rc_assert(hr == S_OK, E_FAIL)

	return hr;
}
std_method_impl CBrokerImpl::UnInit()
{
	HRESULT hr = S_OK;

	hr = m_ConnectTimer->Stop();
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_HeartTimer->Stop();
	rc_assert(hr == S_OK, E_FAIL)

	m_ConnectTimer.dispose();

	m_HeartTimer.dispose();

	m_AcceptQueue.auto_clear();

	return hr;
}
std_method_impl CBrokerImpl::PushQueue(IBase* pBase)
{

	/*
	Node* pChannel = ALLOC_NEW Node();
	rc_assert(pChannel != NULL, E_FAIL)

	hr = pChannel->channel.AttachCChannel(m_pRot, pSocket);
	rc_assert(hr == S_OK, E_FAIL)

	_lComPtr<IBase> pBase;
	hr = this->QueryInterface(IID_IBase, (void**)&pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = pChannel->channel.BindEvent(pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_AcceptQueue.push_queue(pChannel);
	rc_assert(hr == S_OK, E_FAIL)
	*/


	return S_OK;
}
